﻿#region Using directives
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using AlphaMobileControls;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using gpsMe.Utils;
#endregion

namespace gpsMe.Classes
{
    /// <summary>
    /// Grid of the displayed map when navigating
    /// </summary>
    public class gpsMeMapImageGrid
    {
        #region Instance
        /// <summary>
        /// Current gpsMeMapImageGrid instance
        /// </summary>
        public static gpsMeMapImageGrid Instance { get; private set; }
        #endregion

        #region Accessors
        /// <summary>
        /// ImageGrid of the current location images
        /// 00 01 02 03 04
        /// 05 06 07 08 09
        /// 10 11 12 13 14
        /// 15 16 17 18 19
        /// 20 21 22 23 24
        /// </summary>
        public Hashtable SplittedImageGrid { get; private set; }

        /// <summary>
        /// ImageGrid of the current location
        /// </summary>
        public gpsMeMapImage NormalImageGrid { get; private set; }

        /// <summary>
        /// Specifies if the current location is on the map
        /// </summary>
        public bool LocationIsOnMap { get; private set; }
        #endregion

        #region Constructor
        /// <summary>
        /// gpsMeMapImageGrid default constructor
        /// </summary>
        public gpsMeMapImageGrid()
        {
            Instance = this;
            SplittedImageGrid = new Hashtable();
            int iIterator = 0;
            if (gpsMeMap.Instance.BitmapSplit)
            {
                for (int iHashtableYIterator = 0; iHashtableYIterator < 5; iHashtableYIterator++)
                {
                    for (int iHashtableXIterator = 0; iHashtableXIterator < 5; iHashtableXIterator++)
                    {
                        SplittedImageGrid.Add(iIterator, new gpsMeMapImage(gpsMeMap.Instance.MapPath + @"\" + gpsMeMap.Instance.BitmapCommonName + iHashtableXIterator.ToString() + "." + iHashtableYIterator.ToString() + gpsMeMap.Instance.BitmapExtension));
                        ((gpsMeMapImage)SplittedImageGrid[iIterator]).Image.Location = new Point(iHashtableXIterator * gpsMeMap.Instance.BitmapPartWidth, iHashtableYIterator * gpsMeMap.Instance.BitmapPartHeight);
                        iIterator++;
                    }
                }
            }
            else
            {
                NormalImageGrid = new gpsMeMapImage(gpsMeMap.Instance.MapPath + @"\" + gpsMeMap.Instance.BitmapCommonName + gpsMeMap.Instance.BitmapExtension);
            }
            this.LocationIsOnMap = false;
        }
        #endregion

        #region Methods / Functions / Events
        /// <summary>
        /// Updates the current grid to the location given by parameter
        /// </summary>
        /// <param name="p_oLocationPoint"></param>
        public void UpdateGrid(gpsMeLocationPoint p_oLocationPoint)
        {
            if (gpsMeMap.Instance.BitmapSplit)
            {
                throw new NotImplementedException();
                //Coming with the new framework
                //UpdateSplittedGrid(p_oLocationPoint);
            }
            else
            {
                UpdateNormalGrid(p_oLocationPoint);
            }
        }

        /// <summary>
        /// Updates the splitted grid of images to the location given by parameter
        /// </summary>
        /// <param name="p_oLocationPoint">location point used to choose which images of the map to use, where to place them and places the position cursor</param>
        private void UpdateSplittedGrid(gpsMeLocationPoint p_oLocationPoint)
        {
            Point oLocationPointFromTopLeft;
            bool bLocationIsOnMap;
            GridAndCursorLocationsFromLocation(p_oLocationPoint, out oLocationPointFromTopLeft, out bLocationIsOnMap);
            this.LocationIsOnMap = bLocationIsOnMap;
            int iLocationPointImageNumberX = oLocationPointFromTopLeft.X / gpsMeMap.Instance.BitmapPartWidth;
            if ((oLocationPointFromTopLeft.X % gpsMeMap.Instance.BitmapPartWidth) > 0)
                iLocationPointImageNumberX++;
            int iLocationPointImageNumberY = oLocationPointFromTopLeft.Y / gpsMeMap.Instance.BitmapPartHeight;
            if ((oLocationPointFromTopLeft.Y % gpsMeMap.Instance.BitmapPartHeight) > 0)
                iLocationPointImageNumberY++;
            string sLocationPointImage = gpsMeMap.Instance.BitmapCommonName + iLocationPointImageNumberX.ToString() + "." + iLocationPointImageNumberY.ToString();
            string sLocationPointImagePath = gpsMeMap.Instance.MapPath + @"\" + sLocationPointImage + gpsMeMap.Instance.BitmapExtension;
            if (((gpsMeMapImage)this.SplittedImageGrid[0]).Path != sLocationPointImagePath)
            {
                this.SplittedImageGrid[0] = new gpsMeMapImage(sLocationPointImagePath);
            }
        }

        /// <summary>
        /// Updates the normal grid of images to the location given by parameter
        /// </summary>
        /// <param name="p_oLocationPoint">location point used to place the image representing the map and places the position cursor</param>
        private void UpdateNormalGrid(gpsMeLocationPoint p_oLocationPoint)
        {
            Point oLocationPointFromTopLeft;
            bool bLocationIsOnMap;
            GridAndCursorLocationsFromLocation(p_oLocationPoint, out oLocationPointFromTopLeft, out bLocationIsOnMap);
            this.LocationIsOnMap = bLocationIsOnMap;
            if (this.LocationIsOnMap)
            {
                int iLocationPointXFromTopLeft = oLocationPointFromTopLeft.X;
                int iLocationPointYFromTopLeft = oLocationPointFromTopLeft.Y;

                int iMapX = (iLocationPointXFromTopLeft - (Screen.PrimaryScreen.Bounds.Width / 2)) * (-1);
                if (iMapX < ((gpsMeMap.Instance.TotalBitmapWidth - Screen.PrimaryScreen.Bounds.Width) * (-1)))
                {
                    iMapX = (gpsMeMap.Instance.TotalBitmapWidth - Screen.PrimaryScreen.Bounds.Width) * (-1);
                }
                else if (iMapX > 0)
                {
                    iMapX = 0;
                }
                int iMapY = (iLocationPointYFromTopLeft - (Screen.PrimaryScreen.Bounds.Height / 2)) * (-1);
                if (iMapY < ((gpsMeMap.Instance.TotalBitmapHeight - Screen.PrimaryScreen.Bounds.Height) * (-1)))
                {
                    iMapY = (gpsMeMap.Instance.TotalBitmapHeight - Screen.PrimaryScreen.Bounds.Height) * (-1);
                }
                else if (iMapY > 0)
                {
                    iMapY = 0;
                }
                int iLocationPointX = iMapX + iLocationPointXFromTopLeft;
                int iLocationPointY = iMapY + iLocationPointYFromTopLeft;
                this.NormalImageGrid.Image.Location = new Point(iMapX, iMapY);
                gpsMeCursor.Instance.Location = new Point(iLocationPointX - (gpsMeCursor.Instance.Width / 2), iLocationPointY - (gpsMeCursor.Instance.Height / 2));
            }
        }

        /// <summary>
        /// Returns the map and the cursor position in pixels
        /// </summary>
        /// <param name="p_oLocationPoint">the location point used to locate the map and the cursor</param>
        /// <param name="p_oMapLocation">the returned position of the map</param>
        /// <param name="p_oCursorLocation">the returned location point position on the map</param>
        private void GridAndCursorLocationsFromLocation(gpsMeLocationPoint p_oLocationPoint, out Point p_oLocationPointFromtopLeft, out bool p_bLocationIsOnMap)
        {
            p_oLocationPointFromtopLeft = new Point();
            p_bLocationIsOnMap = false;
            gpsMeLocationPoint oMapLocationTopLeft = null;
            gpsMeLocationPoint oMapLocationBottomRight = null;
            if (gpsMeMap.Instance.LocationMode == gpsMeMap.LOCATION_MODE_TOP_LEFT_BOTTOM_RIGHT)
            {
                if ((p_oLocationPoint.Longitude.DegreesValue >= gpsMeMap.Instance.LocationTopLeft.Longitude.DegreesValue)
                    && (p_oLocationPoint.Longitude.DegreesValue <= gpsMeMap.Instance.LocationBottomRight.Longitude.DegreesValue)
                    && (p_oLocationPoint.Latitude.DegreesValue >= gpsMeMap.Instance.LocationBottomRight.Latitude.DegreesValue)
                    && (p_oLocationPoint.Latitude.DegreesValue <= gpsMeMap.Instance.LocationTopLeft.Latitude.DegreesValue))
                {
                    p_bLocationIsOnMap = true;
                    oMapLocationTopLeft = gpsMeMap.Instance.LocationTopLeft;
                    oMapLocationBottomRight = gpsMeMap.Instance.LocationBottomRight;
                }
                else
                {
                    p_bLocationIsOnMap = false;
                }
            }
            else if (gpsMeMap.Instance.LocationMode == gpsMeMap.LOCATION_MODE_TOP_RIGHT_BOTTOM_LEFT)
            {
                if ((p_oLocationPoint.Longitude.DegreesValue >= gpsMeMap.Instance.LocationBottomLeft.Longitude.DegreesValue)
                    && (p_oLocationPoint.Longitude.DegreesValue <= gpsMeMap.Instance.LocationTopRight.Longitude.DegreesValue)
                    && (p_oLocationPoint.Latitude.DegreesValue >= gpsMeMap.Instance.LocationTopRight.Latitude.DegreesValue)
                    && (p_oLocationPoint.Latitude.DegreesValue <= gpsMeMap.Instance.LocationBottomLeft.Latitude.DegreesValue))
                {
                    p_bLocationIsOnMap = true;
                    oMapLocationTopLeft = new gpsMeLocationPoint(gpsMeMap.Instance.LocationTopRight.Latitude, gpsMeMap.Instance.LocationBottomLeft.Longitude);
                    oMapLocationBottomRight = new gpsMeLocationPoint(gpsMeMap.Instance.LocationBottomLeft.Latitude, gpsMeMap.Instance.LocationTopRight.Longitude);
                }
                else
                {
                    p_bLocationIsOnMap = false;
                }
            }
            else
            {
                // The location mode is unknown by this version of gpsMe
                throw new NotImplementedException();
            }
            if (p_bLocationIsOnMap)
            {
                double dMapLongitudeTopLeftPlus180 = oMapLocationTopLeft.Longitude.DegreesValue + 180;
                double dMapLatitudeTopLeftPlus90 = oMapLocationTopLeft.Latitude.DegreesValue + 90;
                double dMapLongitudeBottomRightPlus180 = oMapLocationBottomRight.Longitude.DegreesValue + 180;
                double dMapLatitudeBottomRightPlus90 = oMapLocationBottomRight.Latitude.DegreesValue + 90;
                double dMapTotalWidthInDecimalDegrees = dMapLongitudeBottomRightPlus180 - dMapLongitudeTopLeftPlus180;
                double dMapTotalHeightInDecimalDegrees = dMapLatitudeTopLeftPlus90 - dMapLatitudeBottomRightPlus90;
                double dLocationPointLongitudeFromTopLeft = (p_oLocationPoint.Longitude.DegreesValue + 180) - dMapLongitudeTopLeftPlus180;
                double dLocationPointLatitudeFromTopLeft = dMapLatitudeTopLeftPlus90 - (p_oLocationPoint.Latitude.DegreesValue + 90);
                double dLongitudeDecimalDegreesPerPixel = (dMapTotalWidthInDecimalDegrees * 1000) / gpsMeMap.Instance.TotalBitmapWidth;
                double dLatitudeDecimalDegreesPerPixel = (dMapTotalHeightInDecimalDegrees * 1000) / gpsMeMap.Instance.TotalBitmapHeight;
                int iLocationPointXFromTopLeft = (int)((dLocationPointLongitudeFromTopLeft * 1000) / dLongitudeDecimalDegreesPerPixel);
                int iLocationPointYFromTopLeft = (int)((dLocationPointLatitudeFromTopLeft * 1000) / dLatitudeDecimalDegreesPerPixel);
                p_oLocationPointFromtopLeft = new Point(iLocationPointXFromTopLeft, iLocationPointYFromTopLeft);
            }
        }
        #endregion
    }
}
